package com.example.service.impl;

import com.example.domain.dto.cart.*;
import com.example.domain.dto.pricelist.PriceListEntryDTO;
import com.example.domain.dto.MoneyDTO;
import com.example.domain.entity.Cart;
import com.example.domain.entity.CartItem;
import com.example.domain.entity.Product;
import com.example.domain.entity.enums.CartStatus;
import com.example.domain.entity.enums.ProductStatus;
import com.example.domain.repository.CartItemRepository;
import com.example.domain.repository.CartRepository;
import com.example.domain.repository.ProductRepository;
import com.example.domain.repository.UnitRepository;
import com.example.domain.valueobject.DiscountResult;
import com.example.domain.valueobject.Money;
import com.example.exception.BusinessException;
import com.example.exception.ErrorCode;
import com.example.exception.ResourceNotFoundException;
import com.example.service.CartService;
import com.example.service.PriceListService;
import com.example.service.PricingService;
import com.example.service.PromotionService;
import com.example.util.IdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 购物车服务实现类
 * 
 * @author Means
 * @since 2025-10-27
 */
@Slf4j
@Service
@Transactional(readOnly = true)
public class CartServiceImpl implements CartService {
    
    private final CartRepository cartRepository;
    private final CartItemRepository cartItemRepository;
    private final ProductRepository productRepository;
    private final PriceListService priceListService;
    private final PromotionService promotionService;
    private final UnitRepository unitRepository;
    private final PricingService pricingService;
    
    public CartServiceImpl(CartRepository cartRepository,
                          CartItemRepository cartItemRepository,
                          ProductRepository productRepository,
                          PriceListService priceListService,
                          PromotionService promotionService,
                          UnitRepository unitRepository,
                          PricingService pricingService) {
        this.cartRepository = cartRepository;
        this.cartItemRepository = cartItemRepository;
        this.productRepository = productRepository;
        this.priceListService = priceListService;
        this.promotionService = promotionService;
        this.unitRepository = unitRepository;
        this.pricingService = pricingService;
    }
    
    // ==================== 购物车管理 ====================
    
    @Override
    @Transactional
    public CartDTO getOrCreateCart(String userId, String sessionId) {
        log.debug("获取或创建购物车: userId={}, sessionId={}", userId, sessionId);

        // 1. 优先通过 userId 查找活跃购物车
        if (userId != null) {
            Optional<Cart> existingCart = cartRepository.findActiveCartByUserId(userId);
            if (existingCart.isPresent()) {
                log.debug("找到用户现有购物车: cartId={}, userId={}", existingCart.get().getId(), userId);
                return CartDTO.from(existingCart.get());
            }
        }

        // 2. 如果用户没有购物车，再通过 sessionId 查找
        if (sessionId != null) {
            Optional<Cart> existingCart = cartRepository.findActiveCartBySessionId(sessionId);
            if (existingCart.isPresent()) {
                log.debug("找到会话现有购物车: cartId={}, sessionId={}", existingCart.get().getId(), sessionId);
                return CartDTO.from(existingCart.get());
            }
        }

        // 3. 如果都不存在，创建新购物车
        log.info("创建新购物车: userId={}, sessionId={}", userId, sessionId);
        Cart cart = new Cart();
        cart.setId(IdGenerator.generate());  // 使用生成的UUID作为购物车ID
        cart.setUserId(userId);
        cart.setSessionId(sessionId);
        cart.setStatus(CartStatus.ACTIVE);
        cart = cartRepository.save(cart);

        log.info("新购物车创建成功: cartId={}, userId={}, sessionId={}", cart.getId(), userId, sessionId);
        return CartDTO.from(cart);
    }
    
    @Override
    public CartDTO getCartById(String cartId) {
        log.debug("查询购物车: cartId={}", cartId);
        
        Cart cart = cartRepository.findById(cartId)
                .orElseThrow(() -> new ResourceNotFoundException("购物车", cartId));
        
        // 查询购物车商品
        List<CartItem> cartItems = cartItemRepository.findByCartId(cartId);
        List<CartItemDTO> itemDTOs = cartItems.stream()
                .map(this::buildCartItemDTO)
                .collect(Collectors.toList());
        
        // 构建完整的CartDTO
        CartDTO cartDTO = CartDTO.from(cart);
        cartDTO.setItems(itemDTOs);
        cartDTO.setItemCount(itemDTOs.size());
        
        // 计算购物车总金额
        calculateCartTotals(cartDTO);
        
        log.debug("购物车查询完成: cartId={}, itemCount={}", cartId, itemDTOs.size());
        return cartDTO;
    }
    
    @Override
    public CartDTO getActiveCartByUser(String userId) {
        log.debug("查询用户活跃购物车: userId={}", userId);
        
        return cartRepository.findActiveCartByUserId(userId)
                .map(cart -> {
                    // 查询购物车商品
                    List<CartItem> cartItems = cartItemRepository.findByCartId(cart.getId());
                    List<CartItemDTO> itemDTOs = cartItems.stream()
                            .map(this::buildCartItemDTO)
                            .collect(Collectors.toList());
                    
                    // 构建完整的CartDTO
                    CartDTO cartDTO = CartDTO.from(cart);
                    cartDTO.setItems(itemDTOs);
                    cartDTO.setItemCount(itemDTOs.size());
                    
                    // 计算购物车总金额
                    calculateCartTotals(cartDTO);
                    
                    return cartDTO;
                })
                .orElse(null);
    }
    
    
    @Override
    @Transactional
    public void clearCart(String cartId) {
        log.info("清空购物车: cartId={}", cartId);
        
        // 1. 检查购物车是否存在
        if (!cartRepository.findById(cartId).isPresent()) {
            throw new ResourceNotFoundException("购物车", cartId);
        }
        
        // 2. 删除所有购物车商品
        List<CartItem> items = cartItemRepository.findByCartId(cartId);
        cartItemRepository.deleteAll(items);
        
        log.info("购物车已清空: cartId={}", cartId);
    }
    
    
    // ==================== 购物车商品管理 ====================
    
    @Override
    @Transactional
    public CartDTO addItemToCart(String cartId, AddToCartRequest request) {
        log.info("添加商品到购物车: cartId={}, productId={}, quantity={}", 
                cartId, request.getProductId(), request.getQuantity());
        
        // 1. 检查购物车
        Cart cart = cartRepository.findById(cartId)
                .orElseThrow(() -> new ResourceNotFoundException("购物车", cartId));
        
        if (cart.getStatus() != CartStatus.ACTIVE) {
            throw new BusinessException(ErrorCode.CART_INACTIVE, "购物车不可用");
        }
        
        // 2. 检查商品
        Product product = productRepository.findByIdAndNotDeleted(request.getProductId())
                .orElseThrow(() -> new ResourceNotFoundException("商品", request.getProductId()));
        
        if (product.getStatus() != ProductStatus.ACTIVE) {
            throw new BusinessException(ErrorCode.PRODUCT_INACTIVE, "商品未上架");
        }
        
        // 3. 获取商品价格
        PriceListEntryDTO priceEntry = priceListService.getCurrentPrice(request.getProductId());
        if (priceEntry == null) {
            throw new BusinessException(ErrorCode.PRICE_NOT_CONFIGURED, "商品价格未配置");
        }
        
        // TODO: 单位换算功能暂未启用
        // 当前前端固定使用商品基准单位（request.getUnit() == priceEntry.getBaseUnit()）
        // 如需支持用户选择单位（如用"公斤"买"斤"定价的商品），需要：
        // 1. 注入 UnitService
        // 2. 调用 unitService.convertQuantity(request.getQuantity(), request.getUnit(), priceEntry.getBaseUnit())
        // 3. 存储换算后的数量和基准单位
        
        // 4. 检查是否已存在该商品
        CartItem existingItem = cartItemRepository.findByCartIdAndProductId(cartId, request.getProductId())
                .orElse(null);
        
        if (existingItem != null) {
            // 更新数量
            BigDecimal newQuantity = existingItem.getQuantityValue().add(request.getQuantity());
            existingItem.setQuantityValue(newQuantity);
            existingItem.setQuantityUnit(request.getUnit());
            cartItemRepository.save(existingItem);
            log.info("购物车商品数量已更新: itemId={}, newQuantity={}", existingItem.getId(), newQuantity);
        } else {
            // 新增商品
            CartItem newItem = new CartItem();
            newItem.setId(IdGenerator.generate());
            newItem.setCartId(cartId);
            newItem.setProductId(request.getProductId());
            newItem.setQuantityValue(request.getQuantity());
            newItem.setQuantityUnit(request.getUnit());
            // 注意：CartItem不存储价格，价格在查询时从价目表获取
            
            cartItemRepository.save(newItem);
            log.info("购物车商品已添加: itemId={}", newItem.getId());
        }
        
        // 5. 重新计算购物车
        return recalculateCart(cartId);
    }
    
    @Override
    @Transactional
    public CartDTO updateCartItem(String cartItemId, UpdateCartItemRequest request) {
        log.info("更新购物车商品: itemId={}, quantity={}", cartItemId, request.getQuantity());
        
        // 1. 查询购物车商品
        CartItem item = cartItemRepository.findById(cartItemId)
                .orElseThrow(() -> new ResourceNotFoundException("购物车商品", cartItemId));
        
        // 2. 更新数量
        if (request.getQuantity().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException(ErrorCode.INVALID_QUANTITY, "商品数量必须大于0");
        }
        
        item.setQuantityValue(request.getQuantity());
        
        cartItemRepository.save(item);
        
        // 3. 重新计算购物车
        return recalculateCart(item.getCartId());
    }
    
    @Override
    @Transactional
    public CartDTO removeItemFromCart(String cartItemId) {
        log.info("从购物车删除商品: itemId={}", cartItemId);
        
        CartItem item = cartItemRepository.findById(cartItemId)
                .orElseThrow(() -> new ResourceNotFoundException("购物车商品", cartItemId));
        
        String cartId = item.getCartId();
        cartItemRepository.deleteById(cartItemId);
        
        log.info("购物车商品已删除: itemId={}", cartItemId);
        
        return recalculateCart(cartId);
    }
    
    
    
    // ==================== 购物车计算 ====================
    
    @Override
    @Transactional
    public CartDTO recalculateCart(String cartId) {
        log.debug("重新计算购物车金额: cartId={}", cartId);

        // 1. 查询购物车
        Cart cart = cartRepository.findById(cartId)
                .orElseThrow(() -> new ResourceNotFoundException("购物车", cartId));

        // 2. 查询购物车商品，使用完整的 buildCartItemDTO 构建
        List<CartItem> cartItems = cartItemRepository.findByCartId(cartId);
        List<CartItemDTO> itemDTOs = cartItems.stream()
                .map(this::buildCartItemDTO)
                .collect(Collectors.toList());

        // 3. 构建完整的CartDTO
        CartDTO cartDTO = CartDTO.from(cart);
        cartDTO.setItems(itemDTOs);
        cartDTO.setItemCount(itemDTOs.size());

        // 4. 计算购物车总金额（包含促销）
        calculateCartTotals(cartDTO);

        log.debug("购物车金额重新计算完成: itemCount={}, total={}", 
                itemDTOs.size(), cartDTO.getTotal());

        return cartDTO;
    }
    
    @Override
    public int getCartItemCount(String cartId) {
        return cartItemRepository.countByCartId(cartId).intValue();
    }
    
    @Override
    public boolean isCartEmpty(String cartId) {
        return getCartItemCount(cartId) == 0;
    }
    
    
    // ==================== 私有辅助方法 ====================
    
    /**
     * 构建完整的购物车商品项DTO
     * 包含商品信息、价格信息等
     * 
     * @param cartItem 购物车商品项实体
     * @return 完整的CartItemDTO
     */
    private CartItemDTO buildCartItemDTO(CartItem cartItem) {
        // 查询商品信息
        Product product = productRepository.findById(cartItem.getProductId())
                .orElseThrow(() -> new ResourceNotFoundException("商品", cartItem.getProductId()));
        
        // 构建CartItemDTO
        CartItemDTO itemDTO = CartItemDTO.from(cartItem);
        itemDTO.setProductName(product.getName());
        
        // 填充数量的单位名称
        if (itemDTO.getQuantity() != null && itemDTO.getQuantity().getUnit() != null) {
            unitRepository.findByCode(itemDTO.getQuantity().getUnit()).ifPresent(u -> {
                itemDTO.getQuantity().setUnitName(u.getName());
            });
        }
        
        // 查询商品价格
        PriceListEntryDTO priceEntry = priceListService.getCurrentPrice(cartItem.getProductId());
        if (priceEntry != null && priceEntry.getUnitPrice() != null) {
            // 商品在当前价目表中，标记为可用
            itemDTO.setAvailable(true);
            itemDTO.setUnavailableReason(null);
            
            // 设置原价（从价目表获取的基准价格）
            MoneyDTO originalPrice = priceEntry.getUnitPrice();
            itemDTO.setOriginalPrice(originalPrice);
            
            // 计算折扣后的当前价格
            try {
                DiscountResult discountResult = promotionService.calculateItemDiscount(
                        cartItem.getProductId(), originalPrice.getAmount());
                
                if (discountResult.hasDiscount()) {
                    // 有折扣：使用折后价格和折扣描述
                    MoneyDTO currentPrice = MoneyDTO.builder()
                            .amount(discountResult.getDiscountedAmount())
                            .currency(originalPrice.getCurrency())
                            .build();
                    itemDTO.setUnitPrice(currentPrice);
                    itemDTO.setDiscountDesc(discountResult.getDescription());
                } else {
                    // 无折扣，当前价格等于原价
                    itemDTO.setUnitPrice(originalPrice);
                    itemDTO.setDiscountDesc(null);
                }
            } catch (Exception e) {
                log.warn("计算商品折扣失败: productId={}", cartItem.getProductId(), e);
                // 出错时，当前价格等于原价
                itemDTO.setUnitPrice(originalPrice);
                itemDTO.setDiscountDesc(null);
            }
            
            // 计算小计（使用折后价格）
            // 注意：当前假设 cartItem.quantityUnit 与价目表基准单位一致，无需换算
            // 如启用单位换算，此处需先调用 unitService.convertQuantity()
            Money subtotal = pricingService.calculateLineAmount(
                    cartItem.getQuantityValue(), itemDTO.getUnitPrice().getAmount());
            itemDTO.setSubtotal(MoneyDTO.from(subtotal));
            itemDTO.setTotal(itemDTO.getSubtotal());
        } else {
            // 商品不在当前价目表中，标记为不可用
            log.warn("商品不在当前价目表中: productId={}, productName={}", 
                    cartItem.getProductId(), product.getName());
            
            itemDTO.setAvailable(false);
            itemDTO.setUnavailableReason("该商品已下架");
            
            // 将数量设置为0（按需求）
            itemDTO.getQuantity().setValue(BigDecimal.ZERO);
            
            // 价格相关字段设置为0
            itemDTO.setUnitPrice(MoneyDTO.zero());
            itemDTO.setOriginalPrice(MoneyDTO.zero());
            itemDTO.setSubtotal(MoneyDTO.zero());
            itemDTO.setTotal(MoneyDTO.zero());
        }
        
        return itemDTO;
    }
    
    /**
     * 计算购物车总金额
     * 包括小计、折扣、应付总额等
     * 
     * @param cartDTO 购物车DTO
     */
    private void calculateCartTotals(CartDTO cartDTO) {
        if (cartDTO.getItems() == null || cartDTO.getItems().isEmpty()) {
            cartDTO.setSubtotal(MoneyDTO.builder().amount(BigDecimal.ZERO).currency("CNY").build());
            cartDTO.setDiscount(MoneyDTO.builder().amount(BigDecimal.ZERO).currency("CNY").build());
            cartDTO.setItemDiscount(MoneyDTO.builder().amount(BigDecimal.ZERO).currency("CNY").build());
            cartDTO.setThresholdDiscount(MoneyDTO.builder().amount(BigDecimal.ZERO).currency("CNY").build());
            cartDTO.setPromotionSummary(null);
            cartDTO.setTotal(MoneyDTO.builder().amount(BigDecimal.ZERO).currency("CNY").build());
            return;
        }
        
        // 使用PricingService计算原价总金额和折后总金额
        List<Money> originalAmounts = cartDTO.getItems().stream()
                .filter(item -> item.getOriginalPrice() != null && item.getQuantity() != null)
                .map(item -> Money.of(item.getQuantity().getValue().multiply(item.getOriginalPrice().getAmount())))
                .collect(Collectors.toList());
        
        List<Money> discountedAmounts = cartDTO.getItems().stream()
                .filter(item -> item.getSubtotal() != null)
                .map(item -> Money.of(item.getSubtotal().getAmount()))
                .collect(Collectors.toList());
        
        Money originalSubtotal = pricingService.calculateSubtotal(originalAmounts);
        Money discountedSubtotal = pricingService.calculateSubtotal(discountedAmounts);
        
        BigDecimal originalSubtotalAmount = originalSubtotal.getDisplayAmount();
        BigDecimal discountedSubtotalAmount = discountedSubtotal.getDisplayAmount();
        
        // 计算单品优惠金额（原价 - 折后价）
        BigDecimal itemDiscountAmount = originalSubtotalAmount.subtract(discountedSubtotalAmount);
        
        // 计算满减优惠（传入两个金额，让 Service 根据规则配置选择判断基准）
        DiscountResult thresholdDiscount = null;
        try {
            thresholdDiscount = promotionService.calculateThresholdDiscount(
                    discountedSubtotalAmount,    // 折后小计
                    originalSubtotalAmount       // 原价小计
            );
        } catch (Exception e) {
            log.warn("计算满减折扣失败", e);
            thresholdDiscount = DiscountResult.noDiscount(discountedSubtotalAmount);
        }
        
        BigDecimal thresholdDiscountAmount = thresholdDiscount.getDiscountAmount();
        if (thresholdDiscountAmount.compareTo(BigDecimal.ZERO) < 0) {
            thresholdDiscountAmount = BigDecimal.ZERO;
        }
        
        // 汇总总优惠与应付
        BigDecimal totalDiscountAmount = itemDiscountAmount.add(thresholdDiscountAmount);
        Money payable = pricingService.calculatePayableAmount(
                discountedSubtotal, Money.of(thresholdDiscountAmount));
        BigDecimal payableAmount = payable.getDisplayAmount();
        
        cartDTO.setSubtotal(MoneyDTO.builder()
                .amount(originalSubtotalAmount)
                .currency("CNY")
                .build());
        cartDTO.setItemDiscount(MoneyDTO.builder()
                .amount(itemDiscountAmount)
                .currency("CNY")
                .build());
        cartDTO.setThresholdDiscount(MoneyDTO.builder()
                .amount(thresholdDiscountAmount)
                .currency("CNY")
                .build());
        cartDTO.setDiscount(MoneyDTO.builder()
                .amount(totalDiscountAmount)
                .currency("CNY")
                .build());
        cartDTO.setTotal(MoneyDTO.builder()
                .amount(payableAmount)
                .currency("CNY")
                .build());
        
        if (thresholdDiscount.hasDiscount()) {
            cartDTO.setPromotionSummary(thresholdDiscount.getDescription());
        } else {
            cartDTO.setPromotionSummary(null);
        }
    }
}
